#ifndef _DANIEL_KERR_UNIVERSE_H
#define _DANIEL_KERR_UNIVERSE_H

#include "driver.h"
#include "logicUniverse.h"
#include "planetNamer.h"
#include "glstar.h"

#define Y_VAL 5.0			// 10.0
#define MULTI_WIDTH	5.0		// 20.0

#define BG_RED 0.5
#define BG_GREEN 0.5
#define BG_BLUE 0.5

#define FG_RED 0.1
#define FG_GREEN 0.1
#define FG_BLUE 0.1

#define HIGH_RED 0.3
#define HIGH_GREEN 0.3
#define HIGH_BLUE 0.3


struct Path
{
	GLfloat si,ei;
	GLfloat sx,sy,sz;
	GLfloat rotx,roty;
	GLfloat height,weight;
};

struct Planet
{
	GLfloat posx,posy,posz;
	GLfloat rotate;
	GLfloat size;
	GLuint text;
	string texture;
};

class universe_C
{
	public:
		void initialize(int scount)
		{
			srand(unsigned(time(NULL)));

			// Clear All Parts
			numofedges=numofnodes=0;
			node.clear();
			edge.clear();
			belt.close();
			for(unsigned int i=0;i<connected.size();++i)
			{ connected[i].clear(); }
			connected.clear();
			myUni.clear();
			startlocations.clear();
			reference.clear();

			// Read File
			readfile("levels\\curGame.txt");

			// Set All Parts
			setNodes();
			setEdges();
			belt.setStars(scount,uRadius,Y_VAL);
			setStarts();
		}

		void readfile(string fname)
		{
			planetNamer* p = planetNamer::Instance();
			Max_Edge_Length = Max_Planet_Width = 0.0;
			string dummy;
			ifstream ifs(fname.c_str());
			ifs >> dummy;
			ifs>>numofplayers;
			ifs>>numofnodes;

			for(int i=0;i<numofnodes;++i)
			{
				int own,tempforce,tempready;
				string tempName;
				Planet tempPlanet;

				tempPlanet.text=(GLuint)i;
				ifs>>tempPlanet.size;
				ifs>>own>>tempforce>>tempready;
				ifs>>tempPlanet.texture;
				if(tempPlanet.texture=="RANDOM")
				{tempPlanet.texture=randText();}
				node.push_back(tempPlanet);

				ifs>>tempName;
				logicPlanet tempLPlanet((tempName=="RANDOM")?p->genName():tempName);
				tempLPlanet.setOwner(own);
				tempLPlanet.setForce(Force(own,tempforce,tempready));
				tempLPlanet.setRdy(tempready);
				myUni.add(tempLPlanet);

				reference[tempLPlanet.getName()]=i;

				if(tempPlanet.size>Max_Planet_Width)
				{Max_Planet_Width=tempPlanet.size;}
			}

			setConnectedVector(numofnodes);

			int s,e,w;
			while(ifs>>s>>e>>w)
			{
				connected[s][e]=connected[e][s]=w;
				if(w>Max_Edge_Length) {Max_Edge_Length=w;}
			}
			ifs.close();
		}

		void setConnectedVector(int x)
		{
			vector <int> temp;
			for(int j=0;j<x;++j)
			{temp.push_back(-1);}
			for(int k=0;k<x;++k)
			{
				connected.push_back(temp);
				connected[k][k]=0;
			}
		}

		void setNodes()
		{
			uAngle = (2*PI)/numofnodes;
			double r1 = (Max_Planet_Width*MULTI_WIDTH)/sin(uAngle/2.0);
			double r2 = (Max_Planet_Width*MULTI_WIDTH)/(1-cos(uAngle));
			if(r1>r2)	{uRadius=ceil(r1); if(uRadius<5){uRadius=5;}}
			else		{uRadius=ceil(r2); if(uRadius<5){uRadius=5;}}

			for(int i=0;i<numofnodes;++i)
			{
				node[i].posx=uRadius*sin(i*uAngle);
				node[i].posy=(rand()%(int)(Y_VAL*2))-(Y_VAL*((GLfloat)rand()/(GLfloat)RAND_MAX));
				node[i].posz=uRadius*cos(i*uAngle);
				node[i].rotate = 0;
			}
		}

		void setEdges()
		{
			for(int s=0;s<(numofnodes-1);++s)
			{
				for(int e=s+1;e<numofnodes;++e)
				{
					if(connected[s][e]!=-1)
					{
						Path tempPath;

						// Set Start Point
						tempPath.sx=node[s].posx;
						tempPath.sy=node[s].posy;
						tempPath.sz=node[s].posz;
						
						// Set Edge Height
						double ttx = (double)(node[e].posx-node[s].posx);
						double tty = (double)(node[e].posy-node[s].posy);
						double ttz = (double)(node[e].posz-node[s].posz);
						tempPath.height=sqrt(pow(ttx,2.0)+pow(tty,2.0)+pow(ttz,2.0));

						// Set SI, EI, and Weight
						tempPath.si=s;
						tempPath.ei=e;
						tempPath.weight=connected[s][e];

						// Set Edge Angle
						if((s<numofnodes)&&(e<numofnodes))
						{
							// Compute Y Rotation
							if(node[s].posx==node[e].posx)
							{tempPath.roty=90;}
							else if(node[s].posz==node[e].posz)
							{tempPath.roty=180;}
							else
							{
								double tx,ty;
								if(node[s].posx<node[e].posx)
								{
									tx = (double)(node[e].posx-node[s].posx);
									if(node[s].posz>node[e].posz)
									{	
										ty = (double)(node[s].posz-node[e].posz);
										tempPath.roty=((atan(tx/ty)*180)/PI)+180;
									}
									else
									{
										ty = (double)(node[e].posz-node[s].posz);
										tempPath.roty=((atan(ty/tx)*180)/PI)+270;
									}
								}
								else
								{
									tx = (double)(node[s].posx-node[e].posx);
									if(node[s].posz>node[e].posz)
									{
										
										ty = (double)(node[s].posz-node[e].posz);
										tempPath.roty=((atan(ty/tx)*180)/PI)+90;
									}
									else
									{
										ty = (double)(node[e].posz-node[s].posz);
										tempPath.roty=(atan(tx/ty)*180)/PI;
									}
								}
							}

							// Compute X Rotation
							double ty;
							if(node[s].posy==node[e].posy)
							{tempPath.rotx=0.0;}
							else
							{
								double tta = (double)(node[e].posz-node[s].posz);
								double ttb = (double)(node[e].posx-node[s].posx);
								double tth = sqrt(pow(tta,2.0)+pow(ttb,2.0));

								if(node[s].posy>node[e].posy)
								{
									ty = (double)(node[s].posy-node[e].posy);
									tempPath.rotx=((atan(tth/ty)*180)/PI)+270;
								}
								else
								{
									ty = (double)(node[e].posy-node[s].posy);
									tempPath.rotx=((atan(ty/tth)*180)/PI);
								}
							}

							edge.push_back(tempPath);
							++numofedges;
						}
					}
				}
			}	
		}

		void setStarts()
		{
			for(int i=0;i<numofplayers;++i)
			{
				if(myUni.allOwned(i).size())
				{startlocations.push_back(myUni.allOwned(i)[0]);}
				else
				{startlocations.push_back(rand()%numofnodes);}
			}
		}

		// Random Textures
		string randText()
		{
			char buf[5];
			_itoa_s(rand()%39,buf,5,10);
			return ("images/surface"+string(buf)+".jpg");
		}

		// Link Testing Functions
		bool PisLinked(int AtIndex,int TestIndex)
		{return (connected[AtIndex][TestIndex]!=-1);}

		bool EisLinked(int AtIndex,int TestIndex)
		{return ((edge[TestIndex].si==AtIndex)||(edge[TestIndex].ei==AtIndex));}

		// Accessor functions
		int NOE() {return numofedges;}
		int NOP() {return numofnodes;}
		int NOS() {return belt.NOS();}
		int NOPLAY() {return numofplayers;}

		GLfloat ua()		{return uAngle;}
		GLfloat ur()		{return uRadius;}

		GLfloat px(int i)	{return node[i].posx;}				// X coordinate
		GLfloat py(int i)	{return node[i].posy;}				// Y coordinate
		GLfloat pz(int i)	{return node[i].posz;}				// Z coordinate
		GLfloat pr(int i)	{node[i].rotate+=.05; return node[i].rotate;}			// Roation Value
		GLfloat ps(int i)	{return node[i].size;}				// size
		GLuint ptnum(int i)	{return node[i].text;}				// texture number
		GLuint *ptnp(int i)	{return &node[i].text;}				// texture number pointer
		string ptext(int i)	{return node[i].texture;}			// texture
		string pname(int i)	{return myUni.getName(i);}			// name
		int powner(int i)	{return myUni.getOwner(i);}			// owner
		int drn(string temp)	{return reference[temp];}		// Dereference Planet Name

		GLfloat esi(int i)	{return edge[i].si;}				// start index
		GLfloat eei(int i)	{return edge[i].ei;}				// end index
		GLfloat ex(int i)	{return edge[i].sx;}				// X coordinate
		GLfloat ey(int i)	{return edge[i].sy;}				// Y coordinate
		GLfloat ez(int i)	{return edge[i].sz;}				// Z coordinate
		GLfloat erx(int i)	{return edge[i].rotx;}				// X rotation value
		GLfloat ery(int i)	{return edge[i].roty;}				// Y rotation value
		GLfloat eh(int i)	{return edge[i].height;}			// height value
		GLfloat ew(int i)	{return edge[i].weight;}			// weight value
		int weight(int x,int y)	{return connected[x][y];}		// Edge weight
		GLfloat mel()		{return Max_Edge_Length;}			// max edge length

		GLfloat sx(int i)	{return belt.sx(i);}				// X coordinate
		GLfloat sy(int i)	{return belt.sy(i);}				// Y coordinate
		GLfloat sz(int i)	{return belt.sz(i);}				// Z coordinate
		GLfloat sr(int i)	{return belt.sr(i);}				// red value
		GLfloat sg(int i)	{return belt.sg(i);}				// green value
		GLfloat sb(int i)	{return belt.sb(i);}				// blue value
		GLfloat ss(int i)	{return belt.ss(i);}				// size

		logicUniverse *myUniverse() {return &myUni;}
		vector <string> ppinfo(int i) {return myUni.printS(i);}
		vector <int> slocs() {return startlocations;}

		// Mutator
		void TakePlanet(int who,int planetIndex)
		{myUni.setOwner(planetIndex,who);}//node[planetIndex].owner=who;}

	void universe_C::displayConnect(float r, float g, float b)
	{
			// Background Coloring
//			glColor4f(BG_RED,BG_GREEN,BG_BLUE,1.0);	glRectf(25,25,775,575);
//			glColor4f(FG_RED,FG_GREEN,FG_BLUE,1.0);	glRectf(30,30,770,570);
			

			// Draw Edges
			glLineWidth(2.0);
			for(int k=0;k<NOE();++k)
			{
				GLfloat x1 = (sin(ua()*esi(k))*220.0) + (X_DIM/2.0);
				GLfloat y1 = (cos(ua()*esi(k))*220.0) + (Y_DIM/2.0);
				GLfloat x2 = (sin(ua()*eei(k))*220.0) + (X_DIM/2.0);
				GLfloat y2 = (cos(ua()*eei(k))*220.0) + (Y_DIM/2.0);

				glColor4f(ew(k)/mel(),0.0,(mel()-ew(k))/mel(),1.0);
				glBegin(GL_LINES);
					glVertex2f(x1,y1);
					glVertex2f(x2,y2);
				glEnd();
			}
			glLineWidth(1.0);

			// Draw Planets
			for(int i=0;i<NOP();++i)
			{				
				// Planet Shape
				int owner = powner(i);
				if(owner == NEUTRAL)
					glColor4f(r,g,b,1.0);
				else
					glColor4f(pCol[owner][0],pCol[owner][1],pCol[owner][2],1.0);

				glBegin(GL_TRIANGLE_FAN);
					for(int j=0;j<360.0;j+=10.0)
					{
						GLfloat x = (cos((j*PI)/180.0)*20.0) + (sin(ua()*i)*220.0) + (X_DIM/2.0);
						GLfloat y = (sin((j*PI)/180.0)*20.0) + (cos(ua()*i)*220.0) + (Y_DIM/2.0);
						glVertex2f(x,y);
					}
				glEnd();

				// Planet Text
				glColor4f(1.0,1.0,1.0,0.4);
				GLfloat tx = (sin(ua()*i)*220.0) + (X_DIM/2.0);
				GLfloat ty = (cos(ua()*i)*220.0) + (Y_DIM/2.0) - 50.0;
			}
			

	}


	private:
		GLfloat uAngle,uRadius;
		GLfloat Max_Edge_Length;
		GLfloat Max_Planet_Width;

		int numofedges,numofnodes,numofplayers;
		vector <Path> edge;
		vector <Planet> node;
		Star_C belt;

		logicUniverse myUni;

		map <string,int> reference;
		vector < vector <int> > connected;
		vector <int> startlocations;
};

#endif